import unittest
import os
import unittest.mock as mock

from Test.TestCase import isafTestCase as TestCase
from Base.Exploits import Exploit, Option, GLOBAL_OPTS


def suffix(x):
    return "{}_suffix".format(x)


def SUFFIX(x):
    return "{}_SUFFIX".format(x)


class TestExploitFoo(Exploit):
    doo = Option(default=1, description="description_one")
    paa = Option(default=2, description="description_two")


class TestExploitBar(Exploit):
    doo = Option(default=3, description="description_three")
    paa = Option(default=4, description="description_four")


class TestExploitWithValidators(Exploit):
    doo = Option(default="default_value", description="description_three", validators=suffix)
    paa = Option(default="default_value", description="description_three", validators=(suffix, SUFFIX))


class OptionTest(TestCase):
    def setUp(self):
        self.exploit_foo = TestExploitFoo()
        self.exploit_bar = TestExploitBar()
        self.exploit_with_validators = TestExploitWithValidators()
        GLOBAL_OPTS.clear()

    def test_default_value(self):
        """ Test if default value is properly set. """
        self.assertEqual(self.exploit_foo.doo, 1)
        self.assertEqual(self.exploit_foo.paa, 2)
        self.assertEqual(self.exploit_bar.doo, 3)
        self.assertEqual(self.exploit_bar.paa, 4)

    def test_set_value(self):
        """ Test if descriptors are properly set. """
        self.exploit_foo.doo = "doopaa"
        self.exploit_foo.paa = "kajak"

        self.assertEqual(self.exploit_foo.doo, "doopaa")
        self.assertEqual(self.exploit_foo.paa, "kajak")
        self.assertEqual(self.exploit_bar.doo, 3)
        self.assertEqual(self.exploit_bar.paa, 4)

    def test_if_validator_is_NOT_applied_on_default_value(self):
        self.assertEqual(self.exploit_with_validators.doo, "default_value")

    def test_if_validator_is_applied_after_setting_value(self):
        self.exploit_with_validators.doo = "new_value"
        self.assertEqual(self.exploit_with_validators.doo, "new_value_suffix")

    def test_if_validator_is_applied_in_specific_order(self):
        self.exploit_with_validators.paa = "new_value"
        self.assertEqual(self.exploit_with_validators.paa, "new_value_suffix_SUFFIX")

    def test_if_exploit_option_is_picked_up_before_global(self):
        GLOBAL_OPTS['doo'] = 'global_doo'
        self.exploit_bar.doo = 'value'
        self.exploit_foo.doo = 'value'
        self.assertEqual(self.exploit_bar.doo, 'value')
        self.assertEqual(self.exploit_foo.doo, 'value')

    def test_if_global_options_is_picked_up_before_default(self):
        GLOBAL_OPTS['doo'] = 'global_doo'
        self.assertEqual(self.exploit_bar.doo, 'global_doo')
        self.assertEqual(self.exploit_foo.doo, 'global_doo')

    def test_if_validators_are_applied_on_global_options(self):
        GLOBAL_OPTS['doo'] = 'global_doo'
        self.assertEqual(self.exploit_with_validators.doo, 'global_doo_suffix')

    def test_str_representation(self):
        with mock.patch.object(TestExploitFoo, "__module__", new_callable=mock.PropertyMock) as mock_module:
            mock_module.return_value = "icssploit.modules.exploits.foo.bar"
            self.assertEqual(str(TestExploitFoo()), os.path.join('exploits', 'foo', 'bar'))


if __name__ == '__main__':
    unittest.main()
